Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------


Commit 858c029d10085171d397f8b7479b4e2c9765f86f


Parents : 329d1df
Author : Ivan <ivan@quad4.io>
Signature : Signature validation error
Date : 2026-04-13T18:46:59-05:00

feat(electron): implement default context menu for editable content, links, and misspelled words in Electron app

Changes

1 files changed, 79 insertions(+), 0 deletions(-)


Diff

diff --git a/electron/main.js b/electron/main.js
index 9543ed34..70e21aa1 100644
--- a/electron/main.js
+++ b/electron/main.js
@@ -10,6 +10,7 @@ const {
Notification,
powerSaveBlocker,
session,
+ clipboard,
} = require("electron");
const electronPrompt = require("electron-prompt");
const { spawn } = require("child_process");
@@ -308,6 +309,80 @@ ipcMain.handle("pick-directory", async () => {
return filePaths[0];
});
+function attachDefaultContextMenu(browserWindow) {
+ const webContents = browserWindow.webContents;
+ webContents.on("context-menu", (event, params) => {
+ const template = [];
+
+ if (params.isEditable) {
+ template.push(
+ { role: "undo" },
+ { role: "redo" },
+ { type: "separator" },
+ { role: "cut" },
+ { role: "copy" },
+ { role: "paste" },
+ { role: "pasteAndMatchStyle" },
+ { type: "separator" },
+ { role: "selectAll" }
+ );
+ } else if (params.selectionText) {
+ template.push({ role: "copy" });
+ }
+
+ if (params.misspelledWord) {
+ const suggestions = params.dictionarySuggestions || [];
+ if (suggestions.length > 0) {
+ if (template.length > 0) {
+ template.push({ type: "separator" });
+ }
+ for (const suggestion of suggestions) {
+ template.push({
+ label: suggestion,
+ click: () => {
+ webContents.replaceMisspelling(suggestion);
+ },
+ });
+ }
+ }
+ if (template.length > 0) {
+ template.push({ type: "separator" });
+ }
+ template.push({
+ label: "Add to dictionary",
+ click: () => {
+ void webContents.session.addWordToSpellCheckerDictionary(params.misspelledWord);
+ },
+ });
+ }
+
+ if (params.linkURL) {
+ if (template.length > 0) {
+ template.push({ type: "separator" });
+ }
+ template.push({
+ label: "Open link",
+ click: () => {
+ shell.openExternal(params.linkURL);
+ },
+ });
+ template.push({
+ label: "Copy link",
+ click: () => {
+ clipboard.writeText(params.linkURL);
+ },
+ });
+ }
+
+ if (template.length === 0) {
+ return;
+ }
+
+ const menu = Menu.buildFromTemplate(template);
+ menu.popup({ window: browserWindow });
+ });
+}
+
function log(message) {
// log to stdout of this process
console.log(message);
@@ -391,6 +466,10 @@ function createTray() {
}
app.whenReady().then(async () => {
+ app.on("browser-window-created", (event, browserWindow) => {
+ attachDefaultContextMenu(browserWindow);
+ });
+
// Security: Enforce CSP for all requests as a shell-level fallback
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
const responseHeaders = { ...details.responseHeaders };


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────